﻿using System;
using System.IO;
using System.Collections.Generic;
using Commons.Collections;
using NVelocity;
using NVelocity.App;
using NVelocity.Runtime;
using NVelocity.Exception;

namespace KKCai.Core
{
    public sealed class VelocityEngineManager
    {
        #region Fields

        private static bool CACHE = false;

        private static string ENCODING_DEFAULT = "utf-8";

        private static long INTERVAL = 1 * 60;

        private static string RESOURCE_PATH;

        //private static string VM_LIBRARY = "macro.vm";

        private VelocityEngine _Engine = new VelocityEngine();
        

        #endregion

        #region Constructors

        private VelocityEngineManager()
        {
            InitVelocityEngine();
        }

        #endregion

        #region Properties

        public static VelocityEngineManager Instance
        {
            get
            {
                return new Nested().VelocityEngineManager;
            }
        }

        #endregion

        #region Public Methods

        public static void Configuration(string path)
        {
            Configuration(path, "utf-8", false, 0);
        }

        public static void Configuration(string path, long interval)
        {
            Configuration(path, "utf-8", true, interval);
        }

        public static void Configuration(string path, string encoding, bool cache, long interval)
        {
            VelocityEngineManager.RESOURCE_PATH = path;
            VelocityEngineManager.ENCODING_DEFAULT = encoding;
            VelocityEngineManager.CACHE = cache;
            VelocityEngineManager.INTERVAL = interval;
        }

        public string Merge(string templatePath, IDictionary<string, object> dict)
        {
            Template tpl = null;
            
            try
            {
                tpl = _Engine.GetTemplate(templatePath);
                //tpl = Velocity.GetTemplate(templatePath);
            }
            catch (ResourceNotFoundException e) 
            {
                return e.Message + e.StackTrace; 
            }
            catch (ParseErrorException e) 
            {
                return e.Message + e.StackTrace; 
            }
            catch (MethodInvocationException e)
            {
                return e.Message + e.StackTrace; 
            }
            catch (Exception e)
            { 
                return e.Message + e.StackTrace; 
            }

            if (tpl == null)
            {
                return String.Empty;
            }

            VelocityContext context = new VelocityContext();
            
            if (dict != null)
            {
                foreach (KeyValuePair<string, object> item in dict)
                {
                    context.Put(item.Key, item.Value);
                }
            }

            StringWriter writer = new StringWriter();

            tpl.Merge(context, writer);

            return writer.GetStringBuilder().ToString();
        }

        //public string Evaluate(string inString, IDictionary<string, object> dict)
        //{
        //    VelocityContext context = new VelocityContext();

        //    if (dict != null)
        //    {
        //        foreach (KeyValuePair<string, object> item in dict)
        //        {
        //            context.Put(item.Key, item.Value);
        //        }
        //    }

        //    StringWriter writer = new StringWriter();

        //    Velocity.Evaluate(context, writer, String.Empty, inString);

        //    return writer.GetStringBuilder().ToString();
        //}

        #endregion

        #region Private Methods

        private void InitVelocityEngine()
        {
            ExtendedProperties props = new ExtendedProperties();
            //props.AddProperty(RuntimeConstants.RESOURCE_LOADER, "file");
            props.AddProperty(RuntimeConstants.ENCODING_DEFAULT, ENCODING_DEFAULT);
            props.AddProperty(RuntimeConstants.COUNTER_INITIAL_VALUE, 0);
            
            //props.AddProperty(RuntimeConstants.VM_LIBRARY_AUTORELOAD, true);
            //if (!String.IsNullOrEmpty(VelocityEngineManager.VM_LIBRARY))
            //{
            //    props.AddProperty(RuntimeConstants.VM_LIBRARY, VelocityEngineManager.VM_LIBRARY);
            //}

            if (!string.IsNullOrEmpty(VelocityEngineManager.RESOURCE_PATH))
            {
                props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH, VelocityEngineManager.RESOURCE_PATH);
            }
            
            if (VelocityEngineManager.CACHE)
            {
                props.AddProperty(RuntimeConstants.FILE_RESOURCE_LOADER_CACHE, VelocityEngineManager.CACHE);
                props.AddProperty("file.resource.loader.modificationCheckInterval", VelocityEngineManager.INTERVAL);
            }

            _Engine.Init(props);
            //Velocity.Init(props);
        }

        #endregion

        private class Nested
        {
            static Nested() { }
            internal /* static readonly */ VelocityEngineManager VelocityEngineManager = new VelocityEngineManager();
        }

    }
}